package com.uinnova.product.eam.service.fx.impl;

import com.alibaba.fastjson.JSON;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.uinnova.product.eam.comm.model.es.EamCategory;
import com.uinnova.product.eam.config.Env;
import com.uinnova.product.eam.db.VcDiagramDirDao;
import com.uinnova.product.eam.db.bean.DiagramChangeData;
import com.uinnova.product.eam.model.bm.DiagramPrivateAndDesginData;
import com.uinnova.product.eam.model.enums.AssetType;
import com.uinnova.product.eam.service.EamCategorySvc;
import com.uinnova.product.eam.service.FxDiagramSvc;
import com.uinnova.product.eam.service.fx.GeneralPullSvc;
import com.uinnova.product.eam.service.fx.ProcessCiRltSvc;
import com.uinnova.product.eam.service.fx.ProcessDiagramSvc;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.project.base.diagram.comm.diagram.EamDiagramQuery;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uinnova.project.base.diagram.comm.model.ESDiagramDTO;
import com.uinnova.project.db.eam.ESDiagramDao;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.permission.base.SysUser;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class GeneralPullSvcImpl implements GeneralPullSvc {

    @Autowired
    ProcessCiRltSvc processCiRltSvc;

    @Autowired
    ProcessDiagramSvc processDiagramSvc;

    @Autowired
    ESDiagramDao esDiagramDao;

    @Autowired
    VcDiagramDirDao vcDiagramDirDao;

    @Autowired
    EamCategorySvc categorySvc;

    @Autowired
    FxDiagramSvc fxDiagramSvc;

    @Override
    public String generalCheckOutDiagram(String diagramId, Long dirId, Integer actionType, String diagramName) {
        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        // 校验数据是否冲突
        log.info("########## 校验视图CI合法性，视图ID：【{}】", diagramId);
        List<DiagramChangeData> diagramChangeData = fxDiagramSvc.existCheckConflict(Collections.singletonList(diagramId));
        List<String> primaryKeyList = new ArrayList<>();
        for (DiagramChangeData changeData : diagramChangeData) {
            primaryKeyList.add(changeData.getDesginCiInfo().getCi().getCiPrimaryKey());
        }
        if (!CollectionUtils.isEmpty(primaryKeyList)) {
            log.info("########## 解决主键冲突数据primaryKeyList:【{}】", JSON.toJSONString(primaryKeyList));
            fxDiagramSvc.freshBindingEleByDEnergyId(Collections.singletonList(diagramId), primaryKeyList, Env.GENERAL_DIAGRAM_CHECK_OUT);
        }

        log.info("########## 视图进入检出操作ID：【{}】", diagramId);
        List<ESDiagramDTO> esDiagramDTOS = processDiagramSvc.queryDiagramInfoByIds(Collections.singletonList(diagramId));
        DiagramPrivateAndDesginData privateAndDesginDataByDEnergyId = processCiRltSvc.getPrivateAndDesginDataByDEnergyId(esDiagramDTOS, currentUserInfo);
        // 检出 CI RLT 和 视图本身
        List<CcCiInfo> privateCIInfoList = processCiRltSvc.dealCheckOutDiagramCI(privateAndDesginDataByDEnergyId, currentUserInfo.getLoginCode());     // 处理 设计库 / 私有库 CI 数据   当前数据为通过一致性校验结果
        processCiRltSvc.dealCheckOutDiagramRLT(privateAndDesginDataByDEnergyId, privateCIInfoList, currentUserInfo.getLoginCode());
        String checkId = processDiagramSvc.dealCheckOutDiagram(esDiagramDTOS.get(0), dirId, actionType, diagramName, currentUserInfo.getLoginCode());

        return checkId;
    }

    @Override
    public Map<String, Object> existRelateData(String diagramId, Long dirId) {
        Map<String, Object> data = new HashMap<>();

        String dirName = "我的空间";
        if (!BinaryUtils.isEmpty(diagramId)) {
            List<ESDiagramDTO> esDiagramDTOS = processDiagramSvc.queryDiagramInfoByIds(Collections.singletonList(diagramId));
            if (CollectionUtils.isEmpty(esDiagramDTOS)) {
                throw new BinaryException("检出视图信息异常");
            }
            ESDiagramDTO checkDiagramInfo = esDiagramDTOS.get(0);
            // 判断当前检出视图情况 普通视图或模型视图
            EamCategory designCategory = categorySvc.getById(checkDiagramInfo.getDiagram().getDirId(), LibType.DESIGN);
            if (BinaryUtils.isEmpty(designCategory)) {
                throw new BinaryException("视图所属目录状态异常");
            }
            String modelDiagramId = designCategory.getDiagramId();
            Integer type = designCategory.getType();
            if (type != 5) {
                // 普通视图检出
                data.put("checkType", AssetType.DIAGRAM.assetType);
            } else {
                if (!BinaryUtils.isEmpty(modelDiagramId) && modelDiagramId.equals(diagramId)) {
                    throw new BinaryException("请从左侧目录对应的层级检出");
                } else {
                    // 模型视图检出
                    data.put("checkType", AssetType.MODEL.assetType);
                }
            }

            // 根据当前发布视图ID 查找本地是否存在关联的视图
            EamDiagramQuery eamDiagramQuery = new EamDiagramQuery();
            eamDiagramQuery.setIsOpen(0);   // 本地视图
            eamDiagramQuery.setDataStatus(1);
            eamDiagramQuery.setStatus(1);
            eamDiagramQuery.setHistoryVersionFlag(1);
            eamDiagramQuery.setOwnerCodeEqual(SysUtil.getCurrentUserInfo().getLoginCode());
            eamDiagramQuery.setReleaseDiagramId(diagramId);
            List<ESDiagram> listByCdt = esDiagramDao.getListByCdt(eamDiagramQuery);
            Map<String, Object> checkInfo = new HashMap<>();
            if (CollectionUtils.isEmpty(listByCdt)) {
                // 当前本地未查找到关联视图
                data.put("isExist", false);
                checkInfo.put("diagramName", checkDiagramInfo.getDiagram().getName() + "_副本");
                data.put("checkInfo", checkInfo);
            } else {
                data.put("isExist", true);
                checkInfo.put("diagramName", listByCdt.get(0).getName());
                // 查询文件夹名称
                Long privateDirId = listByCdt.get(0).getDirId();
                checkInfo.put("dirId", privateDirId);
                // 兼容应用架构仓库视图检出
                if (Objects.equals(privateDirId, 0L)) {
                    // 不处理
                } else {
                    EamCategory privateCategoryInfo = categorySvc.getById(privateDirId, LibType.PRIVATE);
                    String dirPath = privateCategoryInfo.getDirPath();

                    String[] dirIds = dirPath.split("#");
                    List<String> idsStrs = Arrays.asList(dirIds);
                    List<Long> ids = new ArrayList<>();
                    for (String idStr : idsStrs) {
                        if (!BinaryUtils.isEmpty(idStr)) {
                            ids.add(Long.valueOf(idStr));
                        }
                    }
                    List<EamCategory> privateCategoryList = categorySvc.getByIds(ids, LibType.PRIVATE);
                    privateCategoryList = privateCategoryList.stream().sorted(Comparator.comparing(EamCategory::getDirLvl)).collect(Collectors.toList());
                    for (EamCategory design : privateCategoryList) {
                        dirName = dirName + "/" + design.getDirName();
                    }

                }
                checkInfo.put("dirName", dirName);
                data.put("checkInfo", checkInfo);
            }
        } else {
            // 目录检出
            data.put("checkType", AssetType.MODEL.assetType);
            EamCategory designCategory = categorySvc.getById(dirId, LibType.DESIGN);
            Long modelId = designCategory.getModelId();
            EamCategory modelRoot = categorySvc.getModelRoot(modelId, SysUtil.getCurrentUserInfo().getLoginCode(), LibType.PRIVATE);
            if (BinaryUtils.isEmpty(modelRoot)) {
                data.put("isExist", false);
            } else {
                if (0 == modelRoot.getDataStatus()) {
//                    data.put("isExist", false);
                    throw new BinaryException("检出模型存在于用户回收站,请还原或清除回收站对应的模型数据后在进行检出操作");
                } else {
                    data.put("isExist", true);
                    Map<String, Object> checkInfo = new HashMap<>();
                    EamCategory privateCategoryInfo = categorySvc.getById(modelRoot.getId(), LibType.PRIVATE);
                    String dirPath = privateCategoryInfo.getDirPath();

                    String[] dirIds = dirPath.split("#");
                    List<String> idsStrs = Arrays.asList(dirIds);
                    List<Long> ids = new ArrayList<>();
                    for (String idStr : idsStrs) {
                        if (!BinaryUtils.isEmpty(idStr)) {
                            ids.add(Long.valueOf(idStr));
                        }
                    }
                    List<EamCategory> privateCategoryList = categorySvc.getByIds(ids, LibType.PRIVATE);
                    privateCategoryList = privateCategoryList.stream().sorted(Comparator.comparing(EamCategory::getDirLvl)).collect(Collectors.toList());
                    for (EamCategory design : privateCategoryList) {
                        dirName = dirName + "/" + design.getDirName();
                    }
                    checkInfo.put("dirName", dirName);
                    // 返回根的上一级信息
                    checkInfo.put("dirId", modelRoot.getParentId());
                    data.put("checkInfo", checkInfo);
                }
            }
        }
        return data;
    }

    @Override
    public List<DiagramChangeData> pullCheck(List<String> diagramIds) {
        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        // 获取视图数据
        List<ESDiagramDTO> esDiagramDTOS = processDiagramSvc.queryDiagramInfoByIds(diagramIds);
        // 获取对象数据
        DiagramPrivateAndDesginData privateAndDesginDataByDEnergyId = processCiRltSvc.getPrivateAndDesginDataByDEnergyId(esDiagramDTOS, currentUserInfo);

        Map<String, List<ESDiagramDTO>> userCodeAndDiagramInfoMap = new HashMap<String, List<ESDiagramDTO>>() {
            {
                put(currentUserInfo.getLoginCode(), esDiagramDTOS);
            }
        };

        Map<String, DiagramPrivateAndDesginData> privateAndDesginDataByUserCode = new HashMap<String, DiagramPrivateAndDesginData>() {
            {
                put(currentUserInfo.getLoginCode(), privateAndDesginDataByDEnergyId);
            }
        };

        // 与发布数据主键冲突逻辑相同
        Map<String, List<DiagramChangeData>> resultMap = processCiRltSvc.checkPrimaryKeyConflict(userCodeAndDiagramInfoMap, privateAndDesginDataByUserCode, Boolean.FALSE);

        return resultMap.get(currentUserInfo.getLoginCode());
    }


}
